/*讲解c语言<运算符>的模块*/

/*引入头文件*/
#include <stdbool.h>/*布尔值*/
#include <stdio.h>/*输入输出*/

int main()
{
    /*算术运算符*/
    printf("加: 10 + 5 = %d \n", 10 + 5);
    printf("减: 10 - 5 = %d \n", 10 - 5);
    printf("乘: 10 * 5 = %d \n", 10 * 5);
    printf("除: 10 / 5 = %d \n", 10 / 5);
    printf("余: 10 %% 4 = %d \n", 10 % 4);
    /* "++"或"--"的位置会影响计算顺序
     * 前置会先自增自减计算,再使用值,后置会先使用值,再自增自减计算
     */
    short number = 10;
    printf("自增: %d \n", ++number);/*"++"或"--"写到变量名前是前置,写到变量名后反之*/
    printf("自减: %d \n", --number);

    /* 位运算符
     * 操作二进制位的运算符
     */
    char twos_complement = -0b101010;
    printf("位逻辑反: %d \n", ~twos_complement);
    /* 注意: 对原码,补码,反码不熟可以阅读"document/source_code/main.c"文档
     * 位逻辑反 ~
     * 将<补码>的每一位<取反>,0变1,1变0
     * 二进制"-101010"在char类型中原码为"10101010"
     * 由此推断出反码"11010101"补码"11010110"
     * ~ 再将补码取反就变为"00101001",转换为十进制就是"41"
     */
    char twos_complement_one = -0b1001;
    char twos_complement_two = -0b0110;
    printf("位逻辑异或: %d \n", twos_complement_one ^ twos_complement_two);
    /* 位逻辑异或 ^
     * 对左右数值<补码>的每一位比较,不同为真(true 1),相同为假(false 0)
     * 二进制"-1001"原码"10001001"反码"11110110"补码"11110111",转换十进制是"-9"
     * 二进制"-0110"原码"10000110"反码"11111001"补码"11111010",转换十进制是"-6"
     * "11110111"与"11111010"比较后"00001101",如果正确会输出"13"
     */
    char twos_complement_three = -0b0100;
    char twos_complement_four = -0b0010;
    printf("位逻辑与: %d \n", twos_complement_three & twos_complement_four);
    /* 位逻辑与 &
     * 对左右数值<补码>的每一位比较,都为1是真(true 1),其中一方不为1是假(false 0)
     * 二进制"-0100"原码"10000100"反码"11111011"补码"11111100",转换十进制是"-4"
     * 二进制"-0010"原码"10000010"反码"11111101"补码"11111110",转换十进制是"-2"
     * "11111100"与"11111110"比较后"11111100",如果正确会输出"-4"
     * 注意: 任何数和零配套使用"&"都会被清零
     */
    char twos_complement_five = -0b1111;
    char twos_complement_six = -0b0101;
    printf("位逻辑或: %d \n", twos_complement_five | twos_complement_six);
    /* 位逻辑或 |
     * 对左右数值<补码>的每一位比较,其中一方是1为真(true 1),双方都是0为假(false 0)
     * 二进制"-1111"原码"10001111"反码"11110000"补码"11110001",转换十进制是"-15"
     * 二进制"-0101"原码"10000101"反码"11111010"补码"11111011",转换十进制是"-5"
     * "11110001"与"11111011"比较后"11111011",如果正确会输出"-5"
     * 注意: 任何数和零配套使用"|"都不变
     */
    char twos_complement_seven = -0b111;
    printf("位逻辑左移: %d \n", twos_complement_seven << 3);
    /* 位逻辑左移 <<
     * 左移<补码>的指定位数,空余部分补零,格式: 移动源 << 移动位数
     * 二进制"-111"原码"10000111"反码"11111000"补码"11111001",转换十进制是"-7"
     * "11111001"左移三位后"11001000",如果正确会输出"-56"
     */
    char twos_complement_nine = -0b10;
    printf("位逻辑右移: %d \n",twos_complement_nine >> 3);
    /* 位逻辑右移 >>
     * 右移<补码>的指定位数,空余根据符号补数(正数补0,负数补1),格式: 移动源 >> 移动位数
     * 二进制"-10"原码"10000010"反码"11111101"补码"11111110",转换十进制是"-2"
     * "11111110"右移三位后"11111111",如果正确会输出"-1"
     */

    /* 关系运算符
     * <比较>左右的值并返回(true 1,false 0)的运算符
     */
    printf("大于: %d \n",10 > 5);
    printf("大于等于: %d \n",10 >= 5);
    printf("小于: %d \n",10 < 5);
    printf("小于等于: %d \n",10 <= 5);
    printf("等于: %d \n",10 == 5);
    printf("不等于: %d \n",10 != 5);

    /* 逻辑运算符
     * <连接>关系运算符
     */
    printf("逻辑与: %d \n", 10 != 5 && 10 < 5 && 5 < 10);
    /* 逻辑与 &&
     * 所有关系运算符都为真,结果为真(true 1)
     * 其中一个为假,结果为假(false 0)
     */
    printf("逻辑或: %d \n", 10 == 5 ||  5 > 10 || 5 < 10);
    /* 逻辑与 ||
     * 其中一个关系运算符为真,结果为真(true 1)
     * 所有为假,结果为假(false 0)
     */
    printf("逻辑非: %d \n", ! (10 > 5));
    /* 逻辑非 ! 
     * 括号中的运算符为真,结果为假(false 0)
     * 括号中的运算符为假,结果为真(true 1)
     */
    printf("三元运算符: %d \n", false ? 10 : 15);
    /* 三元运算符
     * 格式: 条件 ? 结果1 : 结果2
     * 条件为真(true 1),返回<结果1>
     * 条件为假(false 0),返回<结果2>
     */
}
